leafmap: biblioteca para análisis geoespacial y mapas interactivos#

Abrir en Colab

NOTA IMPORTANTE

Debido a que los mapas generados con leafmap están diseñados para ejecutarse en cuadernos Jupyter, algunos podrían no apreciarse adecuadamente en páginas HTML estáticas como las de este curso, pero pueden visualizarse también en:

https://colab.research.google.com/github/gf0657-programacionsig/2024-ii/blob/main/contenido/4/leafmap.ipynb

Introducción#

leafmap es una biblioteca de Python para crear visualizaciones interactivas de datos geoespaciales en cuadernos de notas Jupyter. Ha sido desarrollada con base en otras bibliotecas de mapeo como folium, ipyleaflet, maplibre, bokeh, pydeck, kepler.gl y plotly. leafmap proporciona una interfaz de programación de aplicaciones (API) unificada para acceder a las funcionalidades de estas bibliotecas.

En este capítulo se detallan y ejemplifican algunas de las principales capacidades de leafmap.

Instalación#

En ambientes locales (ej. conda)#

Se recomienda actualizar primero conda y mamba.

# Actualizar conda y mamba
conda update conda
conda update -c conda-forge mamba

leafmap puede instalarse con pip, conda o mamba, desde la línea de comandos del sistema operativo. Solo es necesario hacerlo de una forma. Se recomienda instalarla junto con el paquete fiona (para leer y escribir archivos geoespaciales).

# Instalar leafmap con pip
pip install leafmap
# Actualizar leafmap con pip
pip install -U leafmap

# Instalar leafmap con conda
conda install -c conda-forge leafmap
# Actualizar leafmap con conda
conda update -c conda-forge leafmap

# Instalar leafmap con mamba
mamba install -c conda-forge leafmap
# Actualizar leafmap con mamba
mamba update -c conda-forge leafmap

En la nube (ej. Google Colab)#

# Con pip
# !pip install -U leafmap

Carga#

# Carga de leafmap (con el sistema de mapeo de ipyleaflet)
import leafmap

# Carga de geopandas
import geopandas as gpd

# Carga de rasterio
import rasterio

# Carga de numpy
import numpy as np

lefmap proporciona soporte para diversos sistemas de mapeo (plotting backends), incluyendo folium, ipyleaflet, maplibre, bokeh, pydeck, keplergl y plotly. El que se usa por defecto es ipyleaflet.

Si se desea cambiar el sistema de mapeo debe utilizarse una de las siguientes sentencias import.

import leafmap.foliumap as leafmap
import leafmap.bokehmap as leafmap
import leafmap.maplibregl as leafmap
import leafmap.deck as leafmap
import leafmap.kepler as leafmap
import leafmap.plotlymap as leafmap

Operaciones básicas#

Creación y configuraciónb general de mapas#

El constructor de la clase Map crea un mapa interactivo con un mapa base. Por defecto, se utiliza el mapa base de OpenStreetMap.

# Crear un mapa leafmap
m = leafmap.Map()

# Desplegar el mapa
m

El mapa puede ser personalizado con argumentos como center, zoom y height.

# Crear un mapa leafmap personalizado
m = leafmap.Map(
    center=(9.6, -84.2), 
    zoom=7, 
    height="400px"
)

# Desplegar el mapa
m

Por defecto, un mapa leafmap incluye controles para acercamiento/alejamiento, escala, atribución y barra de herramientas. Estos controles pueden activarse y desactivarse.

# Desactivar controles de un mapa leafmap
m = leafmap.Map(
    center=(9.6, -84.2), 
    zoom=7, 
    height="400px",
    zoom_control=True,
    draw_control=False,
    scale_control=False,
    fullscreen_control=False,
    attribution_control=False,
    toolbar_control=False,
)

# Desplegar el mapa
m

El método add_search_control() agrega un control de búsqueda al mapa, el cual permite que los usuarios busquen lugares por sus nombres.

# Dirección del servicio de búsqueda
url = "https://nominatim.openstreetmap.org/search?format=json&q={s}"

# Agregar un control de búsqueda
m.add_search_control(url, position="topleft")

# Desplegar el mapa
m

Manejo de datos vectoriales#

El método add_gdf() agrega un geodataframe como una capa.

# Crear un geodataframe con datos y polígonos de paises
paises_gdf = gpd.read_file(
    'https://github.com/gf0657-programacionsig/2024-ii/raw/refs/heads/main/datos/natural-earth/paises.gpkg'
)
# Crear mapa leafmap
m = leafmap.Map(height="400px")

# Agregar capa base
m.add_basemap("CartoDB.Positron")

# Definir estilo
style = {"color": "black", "fillColor": "black", "fillOpacity": 0.1, "weight": 2}

# Agregar un geodataframe al mapa
m.add_gdf(
    paises_gdf, 
    style=style, 
    layer_name="Países", 
    zoom_to_layer=True
)

# Desplegar el mapa
m

El método add_data() agrega datos vectoriales a un mapa y puede emplear varios esquemas de clasificación. En el siguiente bloque de código se utiliza para generar un mapa de coropletas según la variable de población.

# Crear mapa leafmap
m = leafmap.Map(height="400px")

# Agregar capa de datos vectoriales
m.add_data(
    paises_gdf, 
    column="POP_EST", # columna para el mapa de coropletas
    scheme="Quantiles", # esquema de clasificación
    cmap="Blues", # paleta de colores
    legend_title="Población estimada"
)

# Desplegar el mapa
m

Manejo de datos raster#

El método add_raster() agrega una capa raster al mapa.

# Lectura de datos de altitud
altitud = rasterio.open(
    'https://github.com/gf0657-programacionsig/2024-ii/raw/refs/heads/main/datos/worldclim/altitud.tif'
)
# Crear un objeto Map de leafmap
m = leafmap.Map(
    height="400px",
    center=[altitud.bounds.bottom, altitud.bounds.left], 
    zoom=7
)

# Agregar el raster al mapa
m.add_raster(
    'https://github.com/gf0657-programacionsig/2024-ii/raw/refs/heads/main/datos/worldclim/altitud.tif',
    colormap='terrain',
    layer_name='Capa de Raster'
)

# Desplegar el mapa
m

Los bloques de código siguientes crean un mapa con dos imágenes de satélite.

# URL de la imagen 1
url1 = "https://github.com/gf0657-programacionsig/2024-ii/raw/refs/heads/main/datos/sentinel/gandoca-20240105.tif"
archivo1 = "gandoca-20240105.tif"

# URL de la imagen 2
url2 = "https://github.com/gf0657-programacionsig/2024-ii/raw/refs/heads/main/datos/sentinel/gandoca-20240618.tif"
archivo2 = "gandoca-20240618.tif"

# Descargar las imágenes en archivos locales
leafmap.download_file(url1, archivo1, quiet=True, overwrite=True)
leafmap.download_file(url2, archivo2, quiet=True, overwrite=True)
'/home/mfvargas/gf0657-programacionsig/2024-ii/github/2024-ii/contenido/4/gandoca-20240618.tif'
# Crear el mapa
m = leafmap.Map(height="400px", zoom=20)

# Agregar una capa base
m.add_basemap("CartoDB.Positron")

# Agregar las capas raster con las imágenes
m.add_raster(archivo1, indexes=[4, 3, 2], opacity=0.7, layer_name="2024-01-05")
m.add_raster(archivo2, indexes=[4, 3, 2], opacity=0.7, layer_name="2024-06-18")

# Desplegar el mapa
m

El método split_map() crea un mapa que permite comparar dos capas.

# Crear el mapa
m = leafmap.Map(
    height="400px",
    center=[9.633083, -82.676167], 
    zoom=20
)

# Agregar una capa base
m.add_basemap("CartoDB.Positron")

# Agregar el mapa dividido
m.split_map(
    archivo1,
    archivo2,
    left_label="2024-01-05",
    right_label="2024-06-18",
    left_args={"bands": [4, 3, 2], "opacity": 0.7},
    right_args={"bands": [4, 3, 2], "opacity": 0.7},
)

# Desplegar el mapa
m

Ejercicios#

  1. Despliegue en un mapa leafmap las capas raster correspondientes al Índice de Vegetación de Diferencia Normalizada (NDVI) de las dos imágenes de satélite mostradas en este capítulo en un mapa dividido (split map) y observe las diferencias.

  2. Busque imágenes de dos tiempos diferentes de otra zona afectada por deforestación o avance de la frontera agrícola y observe las diferencias en un mapa dividido. Sugerencias para la elección de la zona: Sierpe, Caño Negro.

  3. Busque imágenes de dos tiempos diferentes de una zona de alto desarrollo urbanístico reciente, calcule su Índice de Diferencia Normalizada Edificada (NDBI) y muestre los resultados en un mapa dividido.